﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace NetDon.OA.Interface
{
    public class FunctionCollection : Collection<Function>
    {
        private readonly Module _module;
        private readonly Function _parentFunction;

        /// <summary>
        /// Initializes a new instance of the <see cref="FunctionCollection"/> class.
        /// </summary>
        /// <param name="module">The module.</param>
        /// <param name="parentFunction">The parent function.</param>
        internal FunctionCollection(Module module, Function parentFunction)
        {
            _module = module;
            _parentFunction = parentFunction;
        }

        /// <summary>
        /// Inserts an element into the <see cref="T:System.Collections.ObjectModel.Collection`1"/> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
        /// <param name="item">The object to insert. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> is less than zero.
        /// -or-
        /// <paramref name="index"/> is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        /// </exception>
        protected override void InsertItem(int index, Function item)
        {
            item.Module = _module;
            item.ParentFunction = _parentFunction;
            base.InsertItem(index, item);
        }

        /// <summary>
        /// Removes the element at the specified index of the <see cref="T:System.Collections.ObjectModel.Collection`1"/>.
        /// </summary>
        /// <param name="index">The zero-based index of the element to remove.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> is less than zero.
        /// -or-
        /// <paramref name="index"/> is equal to or greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        /// </exception>
        protected override void RemoveItem(int index)
        {
            base[index].Module = null;
            base[index].ParentFunction = null;
            base.RemoveItem(index);
        }

        /// <summary>
        /// Replaces the element at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the element to replace.</param>
        /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> is less than zero.
        /// -or-
        /// <paramref name="index"/> is greater than <see cref="P:System.Collections.ObjectModel.Collection`1.Count"/>.
        /// </exception>
        protected override void SetItem(int index, Function item)
        {
            base[index].Module = null;
            base[index].ParentFunction = null;
            item.Module = _module;
            item.ParentFunction = _parentFunction;
            base.SetItem(index, item);
        }

        /// <summary>
        /// Sorts this instance.
        /// </summary>
        public void Sort()
        {
            ((List<Function>)Items).Sort((x, y) => Comparer<int>.Default.Compare(x.Index, y.Index));
        }
    }

    public class Function : ICloneable
    {
        private FunctionCollection _functions;
        private OperationCollection _operations;

        /// <summary>
        /// Gets or sets the function ID.
        /// </summary>
        /// <value>The function ID.</value>
        public string FunctionID { get; set; }

        /// <summary>
        /// Gets or sets the function name.
        /// </summary>
        /// <value>The name.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the navigate URL.
        /// </summary>
        /// <value>The navigate URL.</value>
        public string NavigateUrl { get; set; }

        /// <summary>
        /// Gets or sets the image URL.
        /// </summary>
        /// <value>The image URL.</value>
        public string ImageUrl { get; set; }

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>The description.</value>
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the module.
        /// </summary>
        /// <value>The module.</value>
        public Module Module { get; set; }

        /// <summary>
        /// Gets or sets the parent function.
        /// </summary>
        /// <value>The parent function.</value>
        public Function ParentFunction { get; set; }

        /// <summary>
        /// Gets or sets the index.
        /// </summary>
        /// <value>The index.</value>
        public int Index { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Function"/> is visible.
        /// </summary>
        /// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
        public Boolean Visible { get; set; }

        /// <summary>
        /// Gets the operations.
        /// </summary>
        /// <value>The operations.</value>
        public OperationCollection Operations
        {
            get
            {
                if (_operations == null)
                {
                    _operations = new OperationCollection(this);
                }
                return _operations;
            }
        }

        /// <summary>
        /// Gets the child functions.
        /// </summary>
        /// <value>The functions.</value>
        public FunctionCollection Functions
        {
            get
            {
                if (_functions == null)
                {
                    _functions = new FunctionCollection(Module, this);
                }
                return _functions;
            }
        }

        #region ICloneable Members

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public object Clone()
        {
            return new Function
                       {
                           FunctionID = FunctionID,
                           Name = Name,
                           NavigateUrl = NavigateUrl,
                           ImageUrl = ImageUrl,
                           Index = Index,
                           Visible = Visible,
                           Description = Description
                       };
        }

        #endregion

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return FunctionID;
        }
    }
}